/**
 * slider 滑块组件
 */

layui.define('jquery', function (exports) {
  'use strict';

  var $ = layui.$

  // 外部接口
  var slider = {
    config: {}
    , index: layui.slider ? (layui.slider.index + 10000) : 0

    // 设置全局项
    , set: function (options) {
      var that = this;
      that.config = $.extend({}, that.config, options);
      return that;
    }

    // 事件
    , on: function (events, callback) {
      return layui.onevent.call(this, MOD_NAME, events, callback);
    }
  };

  // 操作当前实例
  var thisSlider = function () {
    var that = this
        , options = that.config;

    return {
      setValue: function (value, index) { // 设置值
        value = value > options.max ? options.max : value;
        value = value < options.min ? options.min : value;
        options.value = value;
        return that.slide('set', value, index || 0);
      }
      , config: options
    }
  };

  // 字符常量
  var MOD_NAME = 'slider';
  var DISABLED = 'layui-disabled';
  var ELEM_VIEW = 'layui-slider';
  var SLIDER_BAR = 'layui-slider-bar';
  var SLIDER_WRAP = 'layui-slider-wrap';
  var SLIDER_WRAP_BTN = 'layui-slider-wrap-btn';
  var SLIDER_TIPS = 'layui-slider-tips';
  var SLIDER_INPUT = 'layui-slider-input';
  var SLIDER_INPUT_TXT = 'layui-slider-input-txt';
  var SLIDER_INPUT_BTN = 'layui-slider-input-btn';
  var ELEM_HOVER = 'layui-slider-hover';

  // 构造器
  var Class = function (options) {
    var that = this;
    that.index = ++slider.index;
    that.config = $.extend({}, that.config, slider.config, options);
    that.render();
  };

  // 默认配置
  Class.prototype.config = {
    type: 'default' //滑块类型，垂直：vertical
    , min: 0 //最小值
    , max: 100 //最大值，默认100
    , value: 0 //初始值，默认为0
    , step: 1 //间隔值
    , showstep: false //间隔点开启
    , tips: true //文字提示，开启
    , input: false //输入框，关闭
    , range: false //范围选择，与输入框不能同时开启，默认关闭
    , height: 200 //配合 type:"vertical" 使用，默认200px
    , disabled: false //滑块禁用，默认关闭
    , theme: '#009688' //主题颜色
  };

  //滑块渲染
  Class.prototype.render = function () {
    var that = this
        , options = that.config;

    //间隔值不能小于 1
    if (options.step < 1) {
      options.step = 1;
    }

    //最大值不能小于最小值
    if (options.max < options.min) {
      options.max = options.min + options.step;
    }

    //判断是否开启双滑块
    if (options.range) {
      options.value = typeof (options.value) == 'object' ? options.value
          : [options.min, options.value];
      var minValue = Math.min(options.value[0], options.value[1])
          , maxValue = Math.max(options.value[0], options.value[1]);
      options.value[0] = minValue > options.min ? minValue : options.min;
      options.value[1] = maxValue > options.min ? maxValue : options.min;
      options.value[0] = options.value[0] > options.max ? options.max
          : options.value[0];
      options.value[1] = options.value[1] > options.max ? options.max
          : options.value[1];

      var scaleFir = Math.floor(
          (options.value[0] - options.min) / (options.max - options.min) * 100)
          , scaleSec = Math.floor(
          (options.value[1] - options.min) / (options.max - options.min) * 100)
          , scale = scaleSec - scaleFir + '%';
      scaleFir = scaleFir + '%';
      scaleSec = scaleSec + '%';
    } else {
      //如果初始值是一个数组，则获取数组的最小值
      if (typeof options.value == 'object') {
        options.value = Math.min.apply(null, options.value);
      }

      //初始值不能小于最小值且不能大于最大值
      if (options.value < options.min) {
        options.value = options.min;
      }
      if (options.value > options.max) {
        options.value = options.max;
      }

      var scale = Math.floor(
          (options.value - options.min) / (options.max - options.min) * 100)
          + '%';
    }
    ;

    //如果禁用，颜色为统一的灰色
    var theme = options.disabled ? '#c2c2c2' : options.theme;

    //滑块
    var temp = '<div class="layui-slider ' + (options.type === 'vertical'
        ? 'layui-slider-vertical' : '') + '">' + (options.tips ? '<div class="'
        + SLIDER_TIPS + '"></div>' : '') +
        '<div class="layui-slider-bar" style="background:' + theme + '; '
        + (options.type === 'vertical' ? 'height' : 'width') + ':' + scale + ';'
        + (options.type === 'vertical' ? 'bottom' : 'left') + ':' + (scaleFir
            || 0) + ';"></div><div class="layui-slider-wrap" style="'
        + (options.type === 'vertical' ? 'bottom' : 'left') + ':' + (scaleFir
            || scale) + ';">' +
        '<div class="layui-slider-wrap-btn" style="border: 2px solid ' + theme
        + ';"></div></div>' + (options.range
            ? '<div class="layui-slider-wrap" style="' + (options.type
            === 'vertical' ? 'bottom' : 'left') + ':' + scaleSec
            + ';"><div class="layui-slider-wrap-btn" style="border: 2px solid '
            + theme + ';"></div></div>' : '') + '</div>';

    var othis = $(options.elem)
        , hasRender = othis.next('.' + ELEM_VIEW);
    //生成替代元素
    hasRender[0] && hasRender.remove(); //如果已经渲染，则Rerender  
    that.elemTemp = $(temp);

    //把数据缓存到滑块上
    if (options.range) {
      that.elemTemp.find('.' + SLIDER_WRAP).eq(0).data('value',
          options.value[0]);
      that.elemTemp.find('.' + SLIDER_WRAP).eq(1).data('value',
          options.value[1]);
    } else {
      that.elemTemp.find('.' + SLIDER_WRAP).data('value', options.value);
    }
    ;

    //插入替代元素
    othis.html(that.elemTemp);

    //垂直滑块
    if (options.type === 'vertical') {
      that.elemTemp.height(options.height + 'px');
    }
    ;

    //显示间断点
    if (options.showstep) {
      var number = (options.max - options.min) / options.step, item = '';
      for (var i = 1; i < number + 1; i++) {
        var step = i * 100 / number;
        if (step < 100) {
          item += '<div class="layui-slider-step" style="' + (options.type
          === 'vertical' ? 'bottom' : 'left') + ':' + step + '%"></div>'
        }
      }
      ;
      that.elemTemp.append(item);
    }
    ;

    //插入输入框
    if (options.input && !options.range) {
      var elemInput = $(
          '<div class="layui-slider-input layui-input"><div class="layui-slider-input-txt"><input type="text" class="layui-input"></div><div class="layui-slider-input-btn"><i class="layui-icon layui-icon-up"></i><i class="layui-icon layui-icon-down"></i></div></div>');
      othis.css("position", "relative");
      othis.append(elemInput);
      othis.find('.' + SLIDER_INPUT_TXT).children('input').val(options.value);
      if (options.type === 'vertical') {
        elemInput.css({
          left: 0
          , top: -48
        });
      } else {
        that.elemTemp.css("margin-right", elemInput.outerWidth() + 15);
      }
    }
    ;

    //给未禁止的滑块滑动事件
    if (!options.disabled) {
      that.slide();
    } else {
      that.elemTemp.addClass(DISABLED);
      that.elemTemp.find('.' + SLIDER_WRAP_BTN).addClass(DISABLED);
    }
    ;

    //划过滑块显示数值
    var timer;
    that.elemTemp.find('.' + SLIDER_WRAP_BTN).on('mouseover', function () {
      var sliderWidth = options.type === 'vertical' ? options.height
          : that.elemTemp[0].offsetWidth
          , sliderWrap = that.elemTemp.find('.' + SLIDER_WRAP)
          , tipsLeft = options.type === 'vertical' ? (sliderWidth - $(
          this).parent()[0].offsetTop - sliderWrap.height()) : $(
          this).parent()[0].offsetLeft
          , left = tipsLeft / sliderWidth * 100
          , value = $(this).parent().data('value')
          , tipsTxt = options.setTips ? options.setTips(value) : value;
      that.elemTemp.find('.' + SLIDER_TIPS).html(tipsTxt);

      clearTimeout(timer);
      timer = setTimeout(function () {
        if (options.type === 'vertical') {
          that.elemTemp.find('.' + SLIDER_TIPS).css({
            "bottom": left + '%',
            "margin-bottom": "20px",
            "display": "inline-block"
          });
        } else {
          that.elemTemp.find('.' + SLIDER_TIPS).css({
            "left": left + '%',
            "display": "inline-block"
          });
        }
        ;
      }, 300);
    }).on('mouseout', function () {
      clearTimeout(timer);
      that.elemTemp.find('.' + SLIDER_TIPS).css("display", "none");
    });
  };

  //滑块滑动
  Class.prototype.slide = function (setValue, value, i) {
    var that = this
        , options = that.config
        , sliderAct = that.elemTemp
        , sliderWidth = function () {
          return options.type === 'vertical' ? options.height
              : sliderAct[0].offsetWidth
        }
        , sliderWrap = sliderAct.find('.' + SLIDER_WRAP)
        , sliderTxt = sliderAct.next('.' + SLIDER_INPUT)
        , inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children(
        'input').val()
        , step = 100 / ((options.max - options.min) / Math.ceil(options.step))
        , change = function (offsetValue, index, from) {
          if (Math.ceil(offsetValue) * step > 100) {
            offsetValue = Math.ceil(offsetValue) * step
          } else {
            offsetValue = Math.round(offsetValue) * step
          }
          ;
          offsetValue = offsetValue > 100 ? 100 : offsetValue;
          offsetValue = offsetValue < 0 ? 0 : offsetValue;
          sliderWrap.eq(index).css(
              (options.type === 'vertical' ? 'bottom' : 'left'), offsetValue + '%');
          var firLeft = valueTo(sliderWrap[0].offsetLeft)
              , secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0;
          if (options.type === 'vertical') {
            sliderAct.find('.' + SLIDER_TIPS).css(
                {"bottom": offsetValue + '%', "margin-bottom": "20px"});
            firLeft = valueTo(
                sliderWidth() - sliderWrap[0].offsetTop - sliderWrap.height());
            secLeft = options.range ? valueTo(
                sliderWidth() - sliderWrap[1].offsetTop - sliderWrap.height()) : 0;
          } else {
            sliderAct.find('.' + SLIDER_TIPS).css("left", offsetValue + '%');
          }
          ;
          firLeft = firLeft > 100 ? 100 : firLeft;
          secLeft = secLeft > 100 ? 100 : secLeft;
          var minLeft = Math.min(firLeft, secLeft)
              , wrapWidth = Math.abs(firLeft - secLeft);
          if (options.type === 'vertical') {
            sliderAct.find('.' + SLIDER_BAR).css(
                {"height": wrapWidth + '%', "bottom": minLeft + '%'});
          } else {
            sliderAct.find('.' + SLIDER_BAR).css(
                {"width": wrapWidth + '%', "left": minLeft + '%'});
          }
          ;
          var selfValue = options.min + Math.round(
              (options.max - options.min) * offsetValue / 100);
          inputValue = selfValue;
          sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(
              inputValue);
          sliderWrap.eq(index).data('value', selfValue);
          sliderAct.find('.' + SLIDER_TIPS).html(
              options.setTips ? options.setTips(selfValue) : selfValue);

          //如果开启范围选择，则返回数组值
          if (options.range) {
            var arrValue = [
              sliderWrap.eq(0).data('value')
              , sliderWrap.eq(1).data('value')
            ];
            if (arrValue[0] > arrValue[1]) {
              arrValue.reverse();
            } //如果前面的圆点超过了后面的圆点值，则调换顺序
          }

          that.value = options.range ? arrValue : selfValue; // 最新值
          options.change && options.change(that.value); // change 回调

          // 值完成选中的事件
          if (from === 'done') {
            options.done && options.done(that.value);
          }
        }
        , valueTo = function (value) {
          var oldLeft = value / sliderWidth() * 100 / step
              , left = Math.round(oldLeft) * step;
          if (value == sliderWidth()) {
            left = Math.ceil(oldLeft) * step;
          }
          ;
          return left;
        }

        //拖拽元素
        , elemMove = $(
        ['<div class="layui-auxiliar-moving" id="LAY-slider-moving"></div'].join(
            ''))
        , createMoveElem = function (move, up) {
          var upCall = function () {
            up && up();
            elemMove.remove();
            options.done && options.done(that.value);
          };
          $('#LAY-slider-moving')[0] || $('body').append(elemMove);
          elemMove.on('mousemove', move);
          elemMove.on('mouseup', upCall).on('mouseleave', upCall);
        };

    //动态赋值
    if (setValue === 'set') {
      return change(value - options.min, i, 'done');
    }

    //滑块滑动
    sliderAct.find('.' + SLIDER_WRAP_BTN).each(function (index) {
      var othis = $(this);
      othis.on('mousedown', function (e) {
        e = e || window.event;

        var oldleft = othis.parent()[0].offsetLeft
            , oldx = e.clientX;
        if (options.type === 'vertical') {
          oldleft = sliderWidth() - othis.parent()[0].offsetTop
              - sliderWrap.height()
          oldx = e.clientY;
        }
        ;

        var move = function (e) {
          e = e || window.event;
          var left = oldleft + (options.type === 'vertical' ? (oldx - e.clientY)
              : (e.clientX - oldx));
          if (left < 0) {
            left = 0;
          }
          if (left > sliderWidth()) {
            left = sliderWidth();
          }
          var reaLeft = left / sliderWidth() * 100 / step;
          change(reaLeft, index);
          othis.addClass(ELEM_HOVER);
          sliderAct.find('.' + SLIDER_TIPS).show();
          e.preventDefault();
        };

        var up = function () {
          othis.removeClass(ELEM_HOVER);
          sliderAct.find('.' + SLIDER_TIPS).hide();
        };

        createMoveElem(move, up)
      });
    });

    // 点击滑块
    sliderAct.on('click', function (e) {
      var main = $('.' + SLIDER_WRAP_BTN);
      var othis = $(this);
      if (!main.is(event.target) && main.has(event.target).length === 0
          && main.length) {
        var index;
        var offset = options.type === 'vertical'
            ? (sliderWidth() - e.clientY + othis.offset().top - $(
                window).scrollTop())
            : (e.clientX - othis.offset().left - $(window).scrollLeft());

        if (offset < 0) {
          offset = 0;
        }
        if (offset > sliderWidth()) {
          offset = sliderWidth();
        }
        var reaLeft = offset / sliderWidth() * 100 / step;
        if (options.range) {
          if (options.type === 'vertical') {
            index = Math.abs(offset - parseInt($(sliderWrap[0]).css('bottom')))
            > Math.abs(offset - parseInt($(sliderWrap[1]).css('bottom'))) ? 1
                : 0;
          } else {
            index = Math.abs(offset - sliderWrap[0].offsetLeft) > Math.abs(
                offset - sliderWrap[1].offsetLeft) ? 1 : 0;
          }
        } else {
          index = 0;
        }
        ;
        change(reaLeft, index, 'done');
        e.preventDefault();
      }
    });

    //点击加减输入框
    sliderTxt.children('.' + SLIDER_INPUT_BTN).children('i').each(
        function (index) {
          $(this).on('click', function () {
            inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children(
                'input').val();
            if (index == 1) { //减
              inputValue = inputValue - options.step < options.min
                  ? options.min
                  : Number(inputValue) - options.step;
            } else {
              inputValue = Number(inputValue) + options.step > options.max
                  ? options.max
                  : Number(inputValue) + options.step;
            }
            ;
            var inputScale = (inputValue - options.min) / (options.max
                - options.min) * 100 / step;
            change(inputScale, 0, 'done');
          });
        });

    //获取输入框值
    var getInputValue = function () {
      var realValue = this.value;
      realValue = isNaN(realValue) ? 0 : realValue;
      realValue = realValue < options.min ? options.min : realValue;
      realValue = realValue > options.max ? options.max : realValue;
      this.value = realValue;
      var inputScale = (realValue - options.min) / (options.max - options.min)
          * 100 / step;
      change(inputScale, 0, 'done');
    };
    sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').on('keydown',
        function (e) {
          if (e.keyCode === 13) {
            e.preventDefault();
            getInputValue.call(this);
          }
        }).on('change', getInputValue);
  };

  //事件处理
  Class.prototype.events = function () {
    var that = this
        , options = that.config;
  };

  //核心入口
  slider.render = function (options) {
    var inst = new Class(options);
    return thisSlider.call(inst);
  };

  exports(MOD_NAME, slider);
})